﻿/* ************************************************************
 * Namespace: JumpFleetGameLib.xMap.SectorMap
 * Class:  SectorMap
 * Author:  Roy Penrod
 * 
 * Class to define a sector map.  Contains a collection
 * of BackgroundLayer objects and ObjectLayer objects.
 * 
 * Implements the xCamera.IMoveableMap interface.
 *  
 * ************************************************************ */

using System;
using Microsoft.Xna.Framework;

namespace JumpFleetGameLib.xMap.SectorMap 
{
    public class SectorMap : JumpFleetGameLib.xCamera.IMoveableMap
    {
        #region MEMBERS

        // tag to identify the sector map
        private string _tag;

        // holds the BackgroundLayer objects
        public BackgroundLayer[] BackgroundLayers;

        // holds the ObjectLayer objects
        public ObjectLayer[] ObjectLayers;

        // top left corner of where the sector map will start drawing
        private Vector2 _currentStartingDrawPosition;

        // width and height of each tile in the tile map
        private int _tileWidth;
        private int _tileHeight;

        // number of columns in the sector map
        private int _columns;

        // number of rows in the sector map
        private int _rows;

        private Vector2 _target;

        #endregion


        #region PROPERTIES

        /// <summary>
        /// Tag to identify the sector map.  Type: string
        /// </summary>
        public string Tag
        {
            get { return _tag; }

            set { _tag = value; }
        }
                
        /// <summary>
        /// Position of the top left corner where the sector map will start drawing.  Type: Vector2
        /// </summary>
        public Vector2 CurrentStartingDrawPosition
        {
            get { return _currentStartingDrawPosition; }

            set 
            { 
                _currentStartingDrawPosition = value;
                SetBackgroundTilePositions();
                SetObjectLayersCurrentMapPosition();
            }
        }

        /// <summary>
        /// Returns the width of a single background tile in the sector map.  Type: int
        /// </summary>
        public int BackgroundTileWidth
        {
            get { return _tileWidth; }
        }

        /// <summary>
        /// Returns the height of a single background tile in the sector map.  Type: int
        /// </summary>
        public int BackgroundTileHeight
        {
            get { return _tileHeight; }
        }

        /// <summary>
        /// Returns the number of columns in the sector map.  Type: int
        /// </summary>
        public int Columns
        {
            get { return _columns; }
        }

        /// <summary>
        /// Returns the number of rows in the sector map.  Type: int
        /// </summary>
        public int Rows
        {
            get { return _rows; }
        }

        /// <summary>
        /// Returns the width in pixels of the sector map.  Type: int
        /// </summary>
        public int WidthInPixels
        {
            get { return _columns * _tileWidth; }
        }

        /// <summary>
        /// Returns the height in pixels of the sector map.  Type: int
        /// </summary>
        public int HeightInPixels
        {
            get { return _rows * _tileHeight; }
        }

        /// <summary>
        /// Returns the bounding box of the sector map.  Type: Rectangle
        /// </summary>
        // implements the xCamera.IMoveableMap interface
        public Rectangle BoundingBox
        {
            get { return new Rectangle( (int)CurrentStartingDrawPosition.X, (int)CurrentStartingDrawPosition.Y, WidthInPixels, HeightInPixels); }
        }

        #endregion


        #region CONSTRUCTORS

        // CurrentDrawPositon defaults to 0, 0

        /// <summary>
        /// Constructor for the SectorMap class.  The CurrentDrawPosition property defaults to 0,0.
        /// </summary>
        /// <param name="tag">Tag to identify the sector map.  Type: string</param>
        /// <param name="numberOfBackgroundLayers">The number of background layers in the sector map.  Type: int</param>
        /// <param name="numberOfObjectLayers">The number of object layers in the sector map.  Type: int</param>
        /// <param name="backgroundTileWidth">The width of a single background tile in the sector map.  Type: int</param>
        /// <param name="backgroundTileHeight">The height of a single background tile in the sector map.  Type: int</param>
        /// <param name="numberOfColumns">The number of columns in the sector map.  Type: int</param>
        /// <param name="numberofRows">The number of rows in the sector map.  Type: int</param>
        public SectorMap(string tag, int numberOfBackgroundLayers, int numberOfObjectLayers, int backgroundTileWidth, int backgroundTileHeight, int numberOfColumns, int numberofRows)
        {
            // assigns the parameters
            _tag = tag;
            _tileWidth = backgroundTileWidth;
            _tileHeight = backgroundTileHeight;
            _columns = numberOfColumns;
            _rows = numberofRows;

            // sets the _currentDrawPosition to a default of 0,0
            _currentStartingDrawPosition = new Vector2(0, 0);

            // creates the array of BackgroundLayer objects
            BackgroundLayers = new BackgroundLayer[numberOfBackgroundLayers];

            // works through the BackgroundLayers array and fills it with BackgroundLayer objects
            for (int layerIndex = 0; layerIndex < numberOfBackgroundLayers; layerIndex++)
                BackgroundLayers[layerIndex] = new BackgroundLayer("", _columns, _rows, 1.0f, _tileWidth, _tileHeight);

            // creates the array of ObjectLayer objects
            ObjectLayers = new ObjectLayer[numberOfObjectLayers];

            // works through the ObjectLayers array and fills it with ObjectLayer objects
            for (int layerIndex = 0; layerIndex < numberOfObjectLayers; layerIndex++)
                ObjectLayers[layerIndex] = new ObjectLayer("", 1.0f);

            _target = new Vector2();
        }

        #endregion


        #region METHODS

        /// <summary>
        /// Sets the Position property for each BackgroundTile object based on the grid size and the top left corner where the SectorMap object will start drawing.
        /// </summary>
        public void SetBackgroundTilePositions()
        {
            // /loop through the Layers array
            for (int layer=0; layer < BackgroundLayers.Length; layer++)
            {
                // loop through the Tiles array (from top to bottom, left to right)
                for (int row = 0; row < BackgroundLayers[layer].Tiles.GetLength(1); row++)
                    for (int column = 0; column < BackgroundLayers[layer].Tiles.GetLength(0); column++)
                        BackgroundLayers[layer].Tiles[column, row].Position = new Vector2( _currentStartingDrawPosition.X + (column * _tileWidth), _currentStartingDrawPosition.Y + (row * _tileHeight));
            }
        }

        /// <summary>
        /// Moves the SectorMap object's CurrentStartingDrawPosition relative to it's CurrentStartingDrawPosition.
        /// </summary>
        /// <param name="numberOfHorizontalPixels">The number of pixels to move the SectorMap object on the horizontal axis. A negative number will move it left.  A positive number will move it right.  Type: int</param>
        /// <param name="numberOfVerticalPixels">The number of pixels to move the SectorMap object on the vertical axis. A negative number will move it up.  A positive number will move it down.  Type: int</param>
        public void MoveSectorMap(int numberOfHorizontalPixels, int numberOfVerticalPixels)
        {
            // sets the new position relative to the current position            
            CurrentStartingDrawPosition = new Vector2(CurrentStartingDrawPosition.X + numberOfHorizontalPixels, CurrentStartingDrawPosition.Y + numberOfVerticalPixels);
        }

        /// <summary>
        /// Moves the sector map by the movement distnace.  
        /// </summary>
        /// <param name="movementDistance">The distance to move the moveable map in pixels.  Type: Vector2</param>
        public void Move(Vector2 movementDistance)
        {
            // sets the new positon relative to the current position
            CurrentStartingDrawPosition = new Vector2( CurrentStartingDrawPosition.X + movementDistance.X, CurrentStartingDrawPosition.Y + movementDistance.Y );
        }

        public void SetTarget(Vector2 target)
        {
            _target = target;
        }

        /// <summary>
        /// Sets the CurrentMapPosition property for each ObjectLayer object to the map's CurrentStartingDrawPosition property.
        /// </summary>
        public void SetObjectLayersCurrentMapPosition()
        {
            // loop through the ObjectLayers array
            for (int layerIndex = 0; layerIndex < ObjectLayers.Length; layerIndex++)
            {
                ObjectLayers[layerIndex].CurrentMapPosition = CurrentStartingDrawPosition;
            }
        }        

        /// <summary>
        /// Calls the Update method for each IUpdatableObject in each ObjectLayer.
        /// </summary>
        /// <param name="gameTime">Microsoft.XNA.Framework.GameTime object</param>
        public void UpdateObjects(GameTime gameTime)
        {
            // go through the PositionableObjectsList in each ObjectLayer
            // and update any objects with the IUpdatableObject interface
            foreach (ObjectLayer objectLayer in ObjectLayers)
                foreach (IPositionableObject positionableObject in objectLayer.PositionableObjectList)
                {
                    //update Ships
                    positionableObject.Target = _target;

                    // check to see if it's an IUpdatableObject
                    IUpdatableObject updatableObject = positionableObject as IUpdatableObject;
                   
                    

                    if (updatableObject != null)
                        updatableObject.Update(gameTime);
                    
                }
        }


        #endregion

    } // <-- end class
} // <-- end namespace
